package com.elitel.common.utils;


import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.util.LocaleUtil;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * 时间工具
 *
 * @author mls
 */
public class DateUtil extends DateUtils {

    private static String[] parsePatterns = new String[]{"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    public static int getYear(Date date) {

        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        return instance.get(Calendar.YEAR);
    }

    public static int getYear() {
        return getYear(new Date());
    }

    /**
     * 获取某年最后一天日期
     *
     * @param year 年份
     * @return Date
     */
    public static Date getYearLast(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        calendar.roll(Calendar.DAY_OF_YEAR, -1);
        return calendar.getTime();
    }

    public static Date getDateBegin(Date date) {
        return parseDate(formatDate(date));
    }


    public static Date getFirstDayDateOfMonth(final Date date) {

        final Calendar cal = Calendar.getInstance();

        cal.setTime(date);

        final int last = cal.getActualMinimum(Calendar.DAY_OF_MONTH);

        cal.set(Calendar.DAY_OF_MONTH, last);

        return cal.getTime();

    }


    public static Date getLastDayOfMonth(final Date date) {

        final Calendar cal = Calendar.getInstance();

        cal.setTime(date);

        final int last = cal.getActualMaximum(Calendar.DAY_OF_MONTH);

        cal.set(Calendar.DAY_OF_MONTH, last);

        return cal.getTime();

    }

    public static int getQuarter(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.MONTH) / 3 + 1;
    }


    public static int getMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.MONTH) + 1;
    }

    public static int getHourOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.HOUR_OF_DAY);
    }

    public static long getDaysBetween(Date startDate, Date endDate) {
        LocalDate sd = LocalDate.of(getYear(startDate), getMonth(startDate), getDayOfMonth(startDate));
        LocalDate ed = LocalDate.of(getYear(endDate), getMonth(endDate), getDayOfMonth(endDate));
        return ChronoUnit.DAYS.between(sd, ed);
    }


    public static void main(String[] args) {
        Date date = new Date();
        Date date1 = addDays(date, -40);
        long dayOfMonth = getDaysBetween(date1, date);
        System.out.println(dayOfMonth);
    }

    public static int getDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    public static String formatDate(Date date) {
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(parsePatterns[0]);
            return dateFormat.format(date);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public static String formatDate(Date date, String pattern) {
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
            return dateFormat.format(date);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public static String formatDateTime(Date date) {
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(parsePatterns[1]);
            return dateFormat.format(date);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public static Date parseDate(String date) {
        if (StringUtils.isEmpty(date)) return null;
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            return dateFormat.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    
    public static Date parseDateTime(String date) {
        if (StringUtils.isEmpty(date)) {
            return null;
        }
        for (String pattern : parsePatterns) {
            try {
                SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
                return dateFormat.parse(date);
            } catch (ParseException ignored) {
                // 忽略异常，继续尝试下一个格式
            }
        }
        return null; // 如果所有格式都无法解析，则返回null
    }


    public static int compareMonth(Date bigDate, Date smallDate) {


        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(bigDate);
        c2.setTime(smallDate);
        int year1 = c1.get(Calendar.YEAR);
        int year2 = c2.get(Calendar.YEAR);
        int month1 = c1.get(Calendar.MONTH);
        int month2 = c2.get(Calendar.MONTH);
        int day1 = c1.get(Calendar.DAY_OF_MONTH);
        int day2 = c2.get(Calendar.DAY_OF_MONTH);
        // 获取年的差值
        int yearInterval = year1 - year2;
        // 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数
        if (month1 < month2 || month1 == month2 && day1 < day2) {
            yearInterval--;
        }
        // 获取月数差值
        int monthInterval = (month1 + 12) - month2;
        if (day1 < day2) {
            monthInterval--;
        }
        monthInterval %= 12;
        int monthsDiff = Math.abs(yearInterval * 12 + monthInterval);
        return monthsDiff;

    }


    public static Long getDayNumBetweenDays(Date startDate, Date endDate) {
        try {
            Long starTime = startDate.getTime();
            Long endTime = endDate.getTime();
            Long num = endTime - starTime;//时间戳相差的毫秒数
            return num / 24 / 60 / 60 / 1000;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Long getHourNumBetweenDays(Date startDate, Date endDate) {
        try {
            Long starTime = startDate.getTime();
            Long endTime = endDate.getTime();
            Long num = endTime - starTime;//时间戳相差的毫秒数
            return num / 60 / 60 / 1000;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    
    public static Long getHourNumBetweenDays(String startDate, String endDate) {
        try {
            Date s = DateUtil.parseDateTime(startDate);
            Date e = DateUtil.parseDateTime(endDate);
            Long starTime = s.getTime();
            Long endTime = e.getTime();
            Long num = endTime - starTime;//时间戳相差的毫秒数
            return num / 60 / 60 / 1000;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static List<Date> getDayList(Date startDate, Date endDate) {
        startDate = parseDate(formatDate(startDate));
        endDate = parseDate(formatDate(endDate));
        List<Date> resDates = new ArrayList<>();
        try {
            //定义日期实例
            Calendar dd = Calendar.getInstance();
            //设置日期起始时间
            dd.setTime(startDate);
            //判断是否到结束日期
            while (dd.getTime().before(endDate)) {
                //输出日期结果
                resDates.add(dd.getTime());
                //进行当前日期月份加1
                dd.add(Calendar.DAY_OF_MONTH, 1);

            }
            //输出日期结果
            resDates.add(endDate);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return resDates;
    }


    public static List<String> getDayListStr(Date startDate, Date endDate) {
        startDate = parseDate(formatDate(startDate));
        endDate = parseDate(formatDate(endDate));
        List<String> resDates = new ArrayList<>();
        try {
            //定义日期实例
            Calendar dd = Calendar.getInstance();
            //设置日期起始时间
            dd.setTime(startDate);
            //判断是否到结束日期
            while (dd.getTime().before(endDate)) {
                //输出日期结果
                resDates.add(formatDate(dd.getTime()));
                //进行当前日期月份加1
                dd.add(Calendar.DAY_OF_MONTH, 1);

            }
            //输出日期结果
            resDates.add(formatDate(endDate));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return resDates;
    }


    public static Date getFirstDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        // 设置年份
        c.set(Calendar.YEAR, c.get(Calendar.YEAR));
        // 设置月份，因为月份从0开始，所以用month - 1
        c.set(Calendar.MONTH, c.get(Calendar.MONTH));
        // 设置日期
        c.set(Calendar.DAY_OF_MONTH, 1);

        return c.getTime();
    }


    public static Date getLastDay(Date date) {
        // 获取Calendar类的实例
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        // 设置年份
        c.set(Calendar.YEAR, c.get(Calendar.YEAR));
        // 设置月份，因为月份从0开始，所以用month - 1
        c.set(Calendar.MONTH, c.get(Calendar.MONTH));
        // 获取当前时间下，该月的最大日期的数字
        int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        // 将获取的最大日期数设置为Calendar实例的日期数
        c.set(Calendar.DAY_OF_MONTH, lastDay);

        return c.getTime();
    }

    public static Date getJavaDate(double date) {
        return getJavaDate(date, false, (TimeZone) null, false);
    }

    public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz) {
        return getJavaDate(date, use1904windowing, tz, false);
    }

    public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz, boolean roundSeconds) {
        Calendar calendar = getJavaCalendar(date, use1904windowing, tz, roundSeconds);
        return calendar == null ? null : calendar.getTime();
    }

    public static Date getJavaDate(double date, boolean use1904windowing) {
        return getJavaDate(date, use1904windowing, (TimeZone) null, false);
    }


    public static Calendar getJavaCalendar(double date) {
        return getJavaCalendar(date, false, (TimeZone) null, false);
    }

    public static Calendar getJavaCalendar(double date, boolean use1904windowing) {
        return getJavaCalendar(date, use1904windowing, (TimeZone) null, false);
    }

    public static Calendar getJavaCalendarUTC(double date, boolean use1904windowing) {
        return getJavaCalendar(date, use1904windowing, LocaleUtil.TIMEZONE_UTC, false);
    }

    public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone) {
        return getJavaCalendar(date, use1904windowing, timeZone, false);
    }

    public static boolean isValidExcelDate(double value) {
        return value > -4.9E-324D;
    }

    public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone, boolean roundSeconds) {
        if (!isValidExcelDate(date)) {
            return null;
        } else {
            int wholeDays = (int) Math.floor(date);
            int millisecondsInDay = (int) ((date - (double) wholeDays) * 8.64E7D + 0.5D);
            Calendar calendar;
            if (timeZone != null) {
                calendar = LocaleUtil.getLocaleCalendar(timeZone);
            } else {
                calendar = LocaleUtil.getLocaleCalendar();
            }

            setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing, roundSeconds);
            return calendar;
        }
    }


    public static void setCalendar(Calendar calendar, int wholeDays, int millisecondsInDay, boolean use1904windowing, boolean roundSeconds) {
        int startYear = 1900;
        int dayAdjust = -1;
        if (use1904windowing) {
            startYear = 1904;
            dayAdjust = 1;
        } else if (wholeDays < 61) {
            dayAdjust = 0;
        }

        calendar.set(startYear, 0, wholeDays + dayAdjust, 0, 0, 0);
        calendar.set(14, millisecondsInDay);
        if (calendar.get(14) == 0) {
            calendar.clear(14);
        }

        if (roundSeconds) {
            calendar.add(14, 500);
            calendar.clear(14);
        }

    }

    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        } else {
            try {
                return parseDate(str.toString(), parsePatterns);
            } catch (ParseException var2) {
                return null;
            }
        }
    }

}
